"""
V2Ray/Xray 链接解析工具
支持解析 vmess://, vless://, trojan:// 等协议链接
"""
import base64
import json
import urllib.parse
from typing import Dict, Optional, Tuple
from api.utils.logger import get_logger

logger = get_logger("v2ray_parser")


class V2RayParser:
    """V2Ray/Xray 协议解析器"""
    
    @staticmethod
    def parse_vmess(link: str) -> Tuple[bool, Optional[Dict], str]:
        """
        解析 vmess:// 链接
        
        格式: vmess://base64(json配置)
        
        Returns:
            (是否成功, 配置字典, 错误信息)
        """
        try:
            if not link.startswith("vmess://"):
                return False, None, "不是有效的vmess链接"
            
            # 移除协议前缀
            encoded = link[8:]
            
            # Base64解码
            try:
                decoded = base64.b64decode(encoded).decode('utf-8')
            except Exception as e:
                # 尝试添加填充
                padding = 4 - len(encoded) % 4
                if padding != 4:
                    encoded += '=' * padding
                decoded = base64.b64decode(encoded).decode('utf-8')
            
            # 解析JSON
            config = json.loads(decoded)
            
            # 提取关键信息
            proxy_config = {
                'type': 'vmess',
                'name': config.get('ps', 'VMess代理'),
                'host': config.get('add', ''),
                'port': int(config.get('port', 443)),
                'uuid': config.get('id', ''),  # VMess的用户ID
                'alter_id': config.get('aid', 0),
                'security': config.get('scy', 'auto'),
                'network': config.get('net', 'tcp'),
                'tls': config.get('tls', '') == 'tls',
                'path': config.get('path', ''),
                'host_header': config.get('host', ''),
                'sni': config.get('sni', ''),
                'full_config': {
                    'type': 'vmess',
                    **config
                }
            }
            
            if not proxy_config['host'] or not proxy_config['uuid']:
                return False, None, "vmess配置缺少必要字段(add或id)"
            
            return True, proxy_config, "解析成功"
            
        except Exception as e:
            logger.error(f"解析vmess链接失败: {e}", exc_info=True)
            return False, None, f"解析失败: {str(e)}"
    
    @staticmethod
    def parse_vless(link: str) -> Tuple[bool, Optional[Dict], str]:
        """
        解析 vless:// 链接
        
        格式: vless://uuid@host:port?parameters#name
        
        Returns:
            (是否成功, 配置字典, 错误信息)
        """
        try:
            if not link.startswith("vless://"):
                return False, None, "不是有效的vless链接"
            
            # 移除协议前缀
            content = link[8:]
            
            # 分离名称
            if '#' in content:
                content, name = content.split('#', 1)
                name = urllib.parse.unquote(name)
            else:
                name = 'VLESS代理'
            
            # 分离参数
            if '?' in content:
                main_part, params_str = content.split('?', 1)
                params = urllib.parse.parse_qs(params_str)
            else:
                main_part = content
                params = {}
            
            # 解析 uuid@host:port
            if '@' not in main_part:
                return False, None, "vless链接格式错误"
            
            uuid, server_part = main_part.split('@', 1)
            
            if ':' not in server_part:
                return False, None, "vless链接缺少端口"
            
            host, port = server_part.rsplit(':', 1)
            
            # 提取所有参数（处理单值）
            def get_param(key, default=''):
                val = params.get(key, [default])
                return val[0] if val else default
            
            proxy_config = {
                'type': 'vless',
                'name': name,
                'host': host,
                'port': int(port),
                'uuid': uuid,
                'encryption': get_param('encryption', 'none'),
                'flow': get_param('flow', ''),  # Flow控制
                'security': get_param('security', 'none'),
                'network': get_param('type', 'tcp'),
                'path': get_param('path'),
                'host_header': get_param('host'),
                'sni': get_param('sni'),
                # Reality专用参数
                'reality': get_param('security') == 'reality',
                'pbk': get_param('pbk'),  # Public key
                'sid': get_param('sid'),  # Short ID
                'fp': get_param('fp'),    # Fingerprint
                'spx': get_param('spx'),  # Spider X (路径)
                'allowInsecure': get_param('allowInsecure', '0'),
                'headerType': get_param('headerType'),
                'full_config': {
                    'type': 'vless',
                    'uuid': uuid,
                    'host': host,
                    'port': int(port),
                    'encryption': get_param('encryption', 'none'),
                    'flow': get_param('flow', ''),
                    'security': get_param('security', 'none'),
                    'network': get_param('type', 'tcp'),
                    'path': get_param('path'),
                    'host_header': get_param('host'),
                    'sni': get_param('sni'),
                    'pbk': get_param('pbk'),
                    'sid': get_param('sid'),
                    'fp': get_param('fp'),
                    'spx': get_param('spx'),
                    'allowInsecure': get_param('allowInsecure', '0'),
                    'headerType': get_param('headerType'),
                    'params': params
                }
            }
            
            return True, proxy_config, "解析成功"
            
        except Exception as e:
            logger.error(f"解析vless链接失败: {e}", exc_info=True)
            return False, None, f"解析失败: {str(e)}"
    
    @staticmethod
    def parse_trojan(link: str) -> Tuple[bool, Optional[Dict], str]:
        """
        解析 trojan:// 链接
        
        格式: trojan://password@host:port?parameters#name
        
        Returns:
            (是否成功, 配置字典, 错误信息)
        """
        try:
            if not link.startswith("trojan://"):
                return False, None, "不是有效的trojan链接"
            
            # 移除协议前缀
            content = link[9:]
            
            # 分离名称
            if '#' in content:
                content, name = content.split('#', 1)
                name = urllib.parse.unquote(name)
            else:
                name = 'Trojan代理'
            
            # 分离参数
            if '?' in content:
                main_part, params_str = content.split('?', 1)
                params = urllib.parse.parse_qs(params_str)
            else:
                main_part = content
                params = {}
            
            # 解析 password@host:port
            if '@' not in main_part:
                return False, None, "trojan链接格式错误"
            
            password, server_part = main_part.split('@', 1)
            
            if ':' not in server_part:
                return False, None, "trojan链接缺少端口"
            
            host, port = server_part.rsplit(':', 1)
            
            proxy_config = {
                'type': 'trojan',
                'name': name,
                'host': host,
                'port': int(port),
                'password': password,
                'security': params.get('security', ['tls'])[0],
                'network': params.get('type', ['tcp'])[0],
                'sni': params.get('sni', [''])[0],
                'path': params.get('path', [''])[0],
                'host_header': params.get('host', [''])[0],
                'full_config': {
                    'type': 'trojan',
                    'password': password,
                    'host': host,
                    'port': int(port),
                    'security': params.get('security', ['tls'])[0],
                    'network': params.get('type', ['tcp'])[0],
                    'sni': params.get('sni', [''])[0],
                    'path': params.get('path', [''])[0],
                    'host_header': params.get('host', [''])[0],
                    'params': params
                }
            }
            
            return True, proxy_config, "解析成功"
            
        except Exception as e:
            logger.error(f"解析trojan链接失败: {e}", exc_info=True)
            return False, None, f"解析失败: {str(e)}"
    
    @staticmethod
    def parse_v2ray_link(link: str) -> Tuple[bool, Optional[Dict], str]:
        """
        自动识别并解析V2Ray链接
        
        Args:
            link: v2ray协议链接 (vmess://, vless://, trojan://)
            
        Returns:
            (是否成功, 配置字典, 错误信息)
        """
        link = link.strip()
        
        if link.startswith("vmess://"):
            return V2RayParser.parse_vmess(link)
        elif link.startswith("vless://"):
            return V2RayParser.parse_vless(link)
        elif link.startswith("trojan://"):
            return V2RayParser.parse_trojan(link)
        else:
            return False, None, "不支持的协议类型，仅支持 vmess://, vless://, trojan://"
    
    @staticmethod
    def config_to_json(config: Dict) -> str:
        """将配置字典转换为JSON字符串存储"""
        return json.dumps(config, ensure_ascii=False)
    
    @staticmethod
    def json_to_config(json_str: str) -> Dict:
        """从JSON字符串恢复配置字典"""
        return json.loads(json_str)
    
    @staticmethod
    def config_to_link(proxy_type: str, config: Dict) -> Tuple[bool, Optional[str], str]:
        """
        将代理配置转换为链接格式
        
        Args:
            proxy_type: 代理类型 (vmess/vless/trojan等)
            config: 配置字典
            
        Returns:
            (是否成功, 链接字符串, 错误信息)
        """
        try:
            if proxy_type == 'vmess':
                return V2RayParser._vmess_to_link(config)
            elif proxy_type == 'vless':
                return V2RayParser._vless_to_link(config)
            elif proxy_type == 'trojan':
                return V2RayParser._trojan_to_link(config)
            else:
                return False, None, f"不支持的代理类型: {proxy_type}"
        except Exception as e:
            logger.error(f"配置转换为链接失败: {e}", exc_info=True)
            return False, None, f"转换失败: {str(e)}"
    
    @staticmethod
    def _vmess_to_link(config: Dict) -> Tuple[bool, str, str]:
        """将VMess配置转换为vmess://链接"""
        try:
            vmess_json = {
                'v': '2',
                'ps': config.get('ps', config.get('name', 'VMess')),
                'add': config.get('add', config.get('host', '')),
                'port': str(config.get('port', 443)),
                'id': config.get('id', config.get('uuid', '')),
                'aid': str(config.get('aid', config.get('alter_id', 0))),
                'scy': config.get('scy', config.get('security', 'auto')),
                'net': config.get('net', config.get('network', 'tcp')),
                'type': config.get('type', config.get('headerType', 'none')),
                'host': config.get('host', config.get('host_header', '')),
                'path': config.get('path', ''),
                'tls': 'tls' if config.get('tls', False) else '',
                'sni': config.get('sni', '')
            }
            
            json_str = json.dumps(vmess_json, ensure_ascii=False)
            encoded = base64.b64encode(json_str.encode('utf-8')).decode('utf-8')
            link = f"vmess://{encoded}"
            return True, link, "转换成功"
        except Exception as e:
            return False, None, f"VMess转换失败: {str(e)}"
    
    @staticmethod
    def _vless_to_link(config: Dict) -> Tuple[bool, str, str]:
        """将VLESS配置转换为vless://链接"""
        try:
            uuid = config.get('uuid', config.get('id', ''))
            host = config.get('host', config.get('add', ''))
            port = config.get('port', 443)
            name = config.get('name', config.get('ps', 'VLESS'))
            
            # 构建参数
            params = {}
            if config.get('encryption'):
                params['encryption'] = config['encryption']
            if config.get('flow'):
                params['flow'] = config['flow']
            if config.get('security'):
                params['security'] = config['security']
            if config.get('network'):
                params['type'] = config['network']
            if config.get('path'):
                params['path'] = config['path']
            if config.get('host_header'):
                params['host'] = config['host_header']
            if config.get('sni'):
                params['sni'] = config['sni']
            if config.get('pbk'):
                params['pbk'] = config['pbk']
            if config.get('sid'):
                params['sid'] = config['sid']
            if config.get('fp'):
                params['fp'] = config['fp']
            if config.get('spx'):
                params['spx'] = config['spx']
            
            # 构建链接
            param_str = urllib.parse.urlencode(params)
            link = f"vless://{uuid}@{host}:{port}"
            if param_str:
                link += f"?{param_str}"
            link += f"#{urllib.parse.quote(name)}"
            
            return True, link, "转换成功"
        except Exception as e:
            return False, None, f"VLESS转换失败: {str(e)}"
    
    @staticmethod
    def _trojan_to_link(config: Dict) -> Tuple[bool, str, str]:
        """将Trojan配置转换为trojan://链接"""
        try:
            password = config.get('password', '')
            host = config.get('host', config.get('add', ''))
            port = config.get('port', 443)
            name = config.get('name', config.get('ps', 'Trojan'))
            
            # 构建参数
            params = {}
            if config.get('security'):
                params['security'] = config['security']
            if config.get('network'):
                params['type'] = config['network']
            if config.get('sni'):
                params['sni'] = config['sni']
            if config.get('path'):
                params['path'] = config['path']
            if config.get('host_header'):
                params['host'] = config['host_header']
            
            # 构建链接
            param_str = urllib.parse.urlencode(params)
            link = f"trojan://{password}@{host}:{port}"
            if param_str:
                link += f"?{param_str}"
            link += f"#{urllib.parse.quote(name)}"
            
            return True, link, "转换成功"
        except Exception as e:
            return False, None, f"Trojan转换失败: {str(e)}"